﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace THO7AlgoritmTimerApplication
{
    class Median11x11Dylan : VisionAlgorithm
    {
        public Median11x11Dylan(String name) : base(name) { }

        public override System.Drawing.Bitmap DoAlgorithm(System.Drawing.Bitmap sourceImage)
        {

            Rectangle rect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
            Bitmap returnImage = (Bitmap)sourceImage.Clone();
            
            BitmapData srcData = sourceImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData desData = returnImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = srcData.Stride;
            int nOffset = stride - sourceImage.Width * 3;
            System.IntPtr Scan0 = srcData.Scan0;
            System.IntPtr DesScan0 = desData.Scan0;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                byte* DesP = (byte*)(void*)DesScan0;
                
                p += stride*5;
                DesP += (stride*5);
                for (int y = 5; y < sourceImage.Height - 5; ++y)
                {
                    p += (3*5);
                    
                    DesP += (3*5);
                    for (int x = 5; x < sourceImage.Width - 5; ++x)
                    {
                        byte[][] pixelList = getList(p, 11, stride, nOffset);
                        quicksort(pixelList[0], 0, pixelList[0].Length - 1);
                        quicksort(pixelList[1], 0, pixelList[1].Length - 1);
                        quicksort(pixelList[2], 0, pixelList[2].Length - 1);

                        DesP[0] = pixelList[0][60];
                        DesP[1] = pixelList[1][60];
                        DesP[2] = pixelList[2][60];


                        p += 3;
                        DesP += 3;


                    }
                    p += 3*5;
                    DesP += 3*5;
               
                    p += nOffset;
                    DesP += nOffset;

                }
            }
            returnImage.UnlockBits(desData);
            sourceImage.UnlockBits(srcData);
            return returnImage;
        }

        private unsafe byte[][] getList(byte* p, int size, int stride, int nOffset)
        {


            byte[][] pixelList = new byte[3][];
            pixelList[0] = new byte[size * size];
            pixelList[1] = new byte[size * size];
            pixelList[2] = new byte[size * size];
            int tempSize = ((size) - 1) / 2;
            p -= tempSize * 3;
            p -= tempSize * stride;
            int count = 0;

            for (int y = -tempSize; y <= tempSize; ++y)
            {
                for (int x = -tempSize; x <= tempSize; ++x)
                {
                    pixelList[0][count] = p[0];
                    pixelList[1][count] = p[1];
                    pixelList[2][count] = p[2];
                    p += 3;
                    count++;

                }

                p += nOffset;

            }
            p -= tempSize * 3;
            p -= tempSize * stride;


            return pixelList;
        }

        private static void quicksort(byte[] items, int left, int right)
        {

            int i, j;
            byte x, y;

            i = left; j = right;
            x = items[(left + right) / 2];
            

            do
            {
                while ((items[i] < x) && (i < right)) i++;
                while ((x < items[j]) && (j > left)) j--;

                if (i <= j)
                {
                    y = items[i];
                    items[i] = items[j];
                    items[j] = y;
                    i++; j--;
                }
            } while (i <= j);

            if (left < j) quicksort(items, left, j);
            if (i < right) quicksort(items, i, right);
        }

    }
}